package SPAN::Model::Method;

use strict;
use warnings;
use base 'Catalyst::Model';
use NEXT;

use Module::Pluggable::Object;
use Text::SimpleTable;

__PACKAGE__->mk_accessors(qw/categories plugins/);

sub new {
    my $self = shift->NEXT::new(@_);
    my ($c) = @_;

    my $locator
        = Module::Pluggable::Object->new( search_path => 'SPAN::Method' );

    my @located = $locator->plugins;
    my @categories;
    my @plugins;

    foreach my $plugin (@located) {
        Catalyst::Utils::ensure_class_loaded($plugin);
        if ( $plugin->can('do_apply') ) {
            push @plugins, $plugin;
        }
        else {
            push @categories, $plugin;
        }
    }

    foreach my $category (@categories) {
        $category = {
            class        => $category,
            display_name => $category->display_name,
            methods      => {
                map {
                    $_->moniker =>
                        { class => $_, display_name => $_->display_name }
                    }
                    grep {/^$category/} @plugins
            }
        };
    }

    $self->categories( \@categories );

    my %plugins;
    foreach my $plugin (@plugins) {
        my $moniker = $plugin->moniker;
        die(      "Can't load $plugin with as '$moniker', "
                . "already loaded as $plugins{$moniker}" )
            if exists $plugins{$moniker};
        $plugins{$moniker} = $plugin;
    }

    $self->plugins( \%plugins );

    my $t = Text::SimpleTable->new( [ 30, 'Category' ], [ 41, 'Method' ] );

    foreach my $category (@categories) {
        $t->row( $category->{class}, '' );

        foreach my $plugin ( values %{ $category->{methods} } ) {
            $t->row( '', $plugin->{class} );
        }
    }

    $c->log->debug( "Loaded SPAN Methods:\n" . $t->draw . "\n" );

    my $t2 = Text::SimpleTable->new( [ 41, 'Method' ], [ 30, 'Moniker' ] );
    foreach my $moniker ( keys %plugins ) {
        $t2->row( $plugins{$moniker}, $moniker );
    }

    $c->log->debug( "SPAN Method Monikers:\n" . $t2->draw . "\n" );

    return $self;
}

sub process {
    my ( $self, $c ) = @_;
    my $method_class = $self->plugins->{ $c->stash->{method} };
    $c->stash->{action} = $method_class->new(
        target_model => $method_class->backend,
        ctx          => $c
    );
}

1;
